package db

import (
	"fmt"
	"time"
	"strings"
	"context"
	"errors"
	"encoding/json"

	"go.etcd.io/etcd/clientv3"
	log "github.com/sirupsen/logrus"
)

var (
	etcdAddr string
	etcdPrefix string
)


func SetDBInfo (address, perfix string) {
	etcdAddr = address
	etcdPrefix = perfix
}

func newClient() *clientv3.Client {
	parsed_db_addr := strings.Split(etcdAddr, ",")
	client, err := clientv3.New(clientv3.Config{
		Endpoints:   parsed_db_addr,
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		log.Error("[ETCD] connect etcd: %s failed, err: %s", parsed_db_addr, err)
	}
	return client
}

func SetKey(key string,  arg interface{}) error {
	cli := newClient()
	kvapi := clientv3.NewKV(cli)
	var (
		err  error
		temp []byte
		data string
	)
	key = fmt.Sprintf("/%s/%s", etcdPrefix, key)
    value, ok := arg.(string)
    if !ok {
		temp, err = json.Marshal(arg)
		if err != nil {
			log.Errorf("[ETCD] Data json serialization error.")
			return errors.New("Etcd data error.")
		}
		data = string(temp)
	} else {
		data = value
	}
	_, err = kvapi.Put(context.Background(), key, data, clientv3.WithPrevKV())
	if err != nil {
		log.Errorf("[ETCD] Data insert etcd error.")
		return errors.New("Etcd insert data error.")
	}
	return nil
}

func GetKey(key string, arg interface{})  (interface{}, error) {
	cli := newClient()
	kvapi := clientv3.NewKV(cli)
	key = fmt.Sprintf("/%s/%s",etcdPrefix, key)
	resp, err := kvapi.Get(context.TODO(), key)
	if err != nil {
		log.Errorf("[ETCD] Get data from etcd error.")
		return "", errors.New("Etcd request data error.")
	}
	_, ok := arg.(bool)
	if !ok {
		result := arg
		json.Unmarshal([]byte(string(resp.Kvs[0].Value)), result)
		return result, nil
	}
	return string(resp.Kvs[0].Value), nil
}



func DelKey(key string) error {
	cli := newClient()
	kvapi := clientv3.NewKV(cli)
	key = fmt.Sprintf("/%s/%s",etcdPrefix, key)
	_, err := kvapi.Delete(context.TODO(), key)
	if err != nil {
		log.Errorf("[ETCD] Del data from etcd error.")
		return errors.New("Etcd delete data error.")
	}
	return nil
}


func IsKeyExist(key string) bool {
	cli := newClient()
	kvapi := clientv3.NewKV(cli)
	key = fmt.Sprintf("/%s/%s",etcdPrefix, key)
	resp, _ := kvapi.Get(context.TODO(), key)
	if len(resp.Kvs) == 0 {
		return false
	}
	return true
}

